#include "animationParseExeConfig.h"

QMultiMap<int, Step*> AnimationParseExeConfig::createDefaultSteps(){
    QMultiMap<int, Step*> steps;

    int time = 0;
    int frameBase = 5;
    steps.insertMulti(0,   new StepReset());

    // 开阀1阀3 注入溶靶液
    time += 1 * frameBase;
    steps.insertMulti(time, new StepValve(1, true));
    steps.insertMulti(time, new StepValve(3, true));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(1, 1, 1, 0));
    steps.insertMulti(time, new StepSyringe(0, -1, 0.5, 0.5));
    time += 30 * frameBase;

    // 延时等待靶材溶解
    time += 30 * frameBase;

    // 关阀1 开阀2 注入调节液
    steps.insertMulti(time, new StepValve(1, false));
    steps.insertMulti(time, new StepValve(2, true));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(2, 1, 1, 0));
    steps.insertMulti(time, new StepSyringe(0, -1, 0.5, 1));
    time += 30 * frameBase;

    // 关阀2阀3 开阀4
    steps.insertMulti(time, new StepValve(2, false));
    steps.insertMulti(time, new StepValve(3, false));
    steps.insertMulti(time, new StepValve(4, true));
    time += 5 * frameBase;

    // 吸入混匀瓶 反复多次
    steps.insertMulti(time, new StepSyringe(0, 1, 1, 0));
    steps.insertMulti(time, new StepSyringe(3, -1, 1, 1));
    time += 30 * frameBase;
    steps.insertMulti(time, new StepSyringe(3, 1, 1, 0));
    steps.insertMulti(time, new StepSyringe(0, -1, 1, 1));
    time += 30 * frameBase;
    steps.insertMulti(time, new StepSyringe(0, 1, 1, 0));
    steps.insertMulti(time, new StepSyringe(3, -1, 1, 1));
    time += 30 * frameBase;
    steps.insertMulti(time, new StepSyringe(3, 1, 1, 0));
    steps.insertMulti(time, new StepSyringe(0, -1, 1, 1));
    time += 30 * frameBase;
    steps.insertMulti(time, new StepSyringe(0, 1, 1, 0));
    steps.insertMulti(time, new StepSyringe(3, -1, 1, 1));
    time += 30 * frameBase;

    // 关阀4 开阀5 6 9 10 推入废液瓶
    steps.insertMulti(time, new StepValve(4, false));
    steps.insertMulti(time, new StepValve(5, true));
    steps.insertMulti(time, new StepValve(6, true));
    steps.insertMulti(time, new StepValve(9, true));
    steps.insertMulti(time, new StepValve(10, true));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(3, 1, 1, 0));
    time += 30 * frameBase;

    // 关阀5 开阀67 推入盐酸
    steps.insertMulti(time, new StepValve(5, false));
    steps.insertMulti(time, new StepValve(6, true));
    steps.insertMulti(time, new StepValve(7, true));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(4, 1, 1, 0));
    time += 30 * frameBase;

    // 关阀6 推入纯水
    steps.insertMulti(time, new StepValve(6, false));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(5, 1, 1, 0));
    time += 30 * frameBase;

    // 关阀7 10 开阀8 11 推入草酸，同时开启检测，收集前产物
    steps.insertMulti(time, new StepValve(7, false));
    steps.insertMulti(time, new StepValve(10, false));
    steps.insertMulti(time, new StepValve(8, true));
    steps.insertMulti(time, new StepValve(11, true));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(6, 1, 0.33, 0.66));
    time += 30 * frameBase;

    // 关9 11 开阀12 13 继续推入草酸，收集中产物
    steps.insertMulti(time, new StepValve(9, false));
    steps.insertMulti(time, new StepValve(11, false));
    steps.insertMulti(time, new StepValve(12, true));
    steps.insertMulti(time, new StepValve(13, true));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(6, 1, 0.33, 0.33));
    time += 30 * frameBase;

    // 关阀13 开阀14 收集后产物
    steps.insertMulti(time, new StepValve(13, false));
    steps.insertMulti(time, new StepValve(14, true));
    time += 5 * frameBase;
    steps.insertMulti(time, new StepSyringe(6, 1, 0.33, 0));
    time += 30 * frameBase;

    // 关闭所有阀门
    steps.insertMulti(time, new StepValve(8, false));
    steps.insertMulti(time, new StepValve(12, false));
    steps.insertMulti(time, new StepValve(14, false));
    time += 5 * frameBase;

    steps.insertMulti(time, new StepWheel(8, -1, 1));
    time += 1.5 * frameBase;
    steps.insertMulti(time, new StepHat());
    time += 1.5 * frameBase;
    steps.insertMulti(time, new StepWheel(7, -1, 1));
    time += 1.5 * frameBase;
    steps.insertMulti(time, new StepHat());

    _maxFrame = time;

    return steps;
}

AnimationParseExeConfig::AnimationParseExeConfig()
{
}

bool AnimationParseExeConfig::startParsing(AnimationState* state, AnimationController* controller, int idx){
    if(isParsing){
        return false;
    }
    _state = state;
    _controller = controller;
    _instrunctionList = data2instruction(1);
//    _stepList = createDefaultSteps();
    _stepList = instruction2step(_instrunctionList);
    execSteps();
    return true;
}

Instruction* AnimationParseExeConfig::query2instruction(const QSqlQuery &query){
    int type = query.value("type").toInt();
    int step = query.value("step").toInt();

    switch (type) {
    case 1:{        // 注射器
        InstructSyringe* instruct = new InstructSyringe;
        instruct->type = type;
        instruct->step = step;

        instruct->idx = query.value("value_1").toInt();
        instruct->direct = query.value("value_4").toString()=="上拉" ? 1 : -1;
        return instruct;
    }
    case 2:{        // 阀门
        InstructValve* instruct = new InstructValve;
        instruct->type = type;
        instruct->step = step;

        QStringList open = query.value("value_1").toString().split(",");
        QStringList close = query.value("value_2").toString().split(",");

        instruct->stateList = QVector<int>(instruct->num, 2);
        foreach(QString o, open){
            int i = o.toInt() - 1;
            if(i >= 0 && i < instruct->num){
                instruct->stateList[i] = 1;
            }
        }foreach(QString c, close){
            int i = c.toInt() - 1;
            if(i >= 0 && i < instruct->num){
                instruct->stateList[i] = 0;
            }
        }
        return instruct;
    }
    case 3:{        // 转盘
        InstructWheel* instruct = new InstructWheel;
        instruct->type = type;
        instruct->step = step;

        instruct->posi = query.value("value_1").toInt();
        instruct->addHat = query.value("value_4").toString() == "是" ? 1 : 0;

        return instruct;
    }
    case 6:{        // 循环
        InstructCycle* instruct = new InstructCycle;
        instruct->type = type;
        instruct->step = 0;     // 循环统一处理

        instruct->start = query.value("value_1").toInt();
        instruct->end =   query.value("value_2").toInt();
        instruct->times = query.value("value_3").toInt();
        return instruct;
    }
    case 4:{    // 检测器
        InstructDetector* instruct = new InstructDetector();
        instruct->type = type;
        instruct->step = step;
        instruct->state = query.value("value_1").toString() == "开" ? true : false;
        return instruct;
    }
    default:{
        Instruction* instruct = new Instruction;
        instruct->step = step;
        instruct->type = 0;
        return instruct;
    }
    }

}

QMultiMap<int, Instruction*>  AnimationParseExeConfig::data2instruction(int idx){

    QSqlDatabase db = dbHelper::openConnection();
    QSqlQuery query(db);

    QString sql = QString("Select * From exe_config Where Id='%1' Order by Type").arg(QString::number(idx));


    QMultiMap<int, Instruction*> instructList;


    bool exeRes = query.exec(sql);

    if(!exeRes){
        Loghelper::getInstance()->WriteLog("ERROR", "ERROR: [Class]AnimationParsing [Func]Data2Instrunction sql-exec-error"+db.lastError().text(), 4);
        return instructList;
    }

    while (query.next()) {
        int step = query.value("Step").toInt();
        if(step <= 0){
            continue;
        }
        Instruction* instruct = query2instruction(query);
        instructList.insert(instruct->step, instruct);
    }
    return instructList;

}

int insertStepFromInstruction(Instruction* instruct, QMultiMap<int, Step*>& steps, int curTime){

    if(!instruct){
        return curTime;
    }

    // 解析时间
    int time_valve = 1;
    int time_syringe = 14;
    int time_wheel = 7;
    int time_hat = 6;
    int time_detector = 1;

    int frameBase = 10;

    if(instruct->type == 1){        // 注射器
        InstructSyringe* ins = (InstructSyringe*)instruct;
        steps.insertMulti(curTime, new StepSyringe(ins->idx, ins->direct, 1, (ins->direct+2)/2));
        curTime += time_syringe * frameBase;
    }else if(instruct->type == 2){      // 阀门
        InstructValve* ins = (InstructValve*)instruct;
        for(int i = 0; i < ins->stateList.size(); i ++){
            if(ins->stateList[i] == 0){
                steps.insertMulti(curTime, new StepValve(i+1, false));
            }if(ins->stateList[i] == 1){
                steps.insertMulti(curTime, new StepValve(i+1, true));
            }
        }
        curTime += time_valve * frameBase;
    }else if(instruct->type == 3){      // 转盘
        InstructWheel* ins = (InstructWheel*)instruct;
        steps.insertMulti(curTime, new StepWheel(ins->posi-1, -1, 1));
        curTime += time_wheel * frameBase;
        if(ins->addHat){
            steps.insertMulti(curTime, new StepHat());
        }
        curTime += time_hat * frameBase;
    }else if(instruct->type == 4){       // 检测器
        InstructDetector* ins = (InstructDetector*)instruct;
        steps.insertMulti(curTime, new StepDetector(ins->state));
        curTime += time_detector * frameBase;
    }

    return curTime;

}

QMultiMap<int, Step*> AnimationParseExeConfig::instruction2step(QMultiMap<int, Instruction*> instructList){


    QMultiMap<int, Step*> steps;



    // 循环
    QVector<int> cycleStart;
    QVector<int> cycleEnd;
    QVector<int> cycleNum;

    QList<Instruction*> i0List = instructList.values(0);
    foreach(Instruction* instruct, i0List){
        if(instruct->type == 6){
            cycleStart.push_back(((InstructCycle*)instruct)->start);
            cycleEnd.push_back(((InstructCycle*)instruct)->end);
            cycleNum.push_back(((InstructCycle*)instruct)->times);
        }
    }

    int maxIdx = instructList.uniqueKeys().back();
    int curTime = 10;


    for(int i = 1; i <= maxIdx; i ++){

        // 处理有循环的情况
        int cycleIdx = cycleStart.indexOf(i);
        if(cycleIdx >= 0){

            int start = cycleStart[cycleIdx];
            int end = cycleEnd[cycleIdx];
            int times = cycleNum[cycleIdx];
            if(start <= 1 || start > maxIdx || end <= 1 || end > maxIdx || start > end || times <= 0){
                continue;
            }
            while(times --){
                for(int s = start; s <= end; s ++){
                    curTime = insertStepFromInstruction(instructList.value(s), steps, curTime);
                }
            }
            i = end;
        }else{
            curTime = insertStepFromInstruction(instructList.value(i), steps, curTime);
        }
    }

    _maxFrame = curTime;

    qDebug() << "解析结果 >>>>>>>>>>>>>>>>>>>>>>>>>>";
    foreach(int key, steps.uniqueKeys()){
        foreach(Step* step, steps.values(key)){
            qDebug() << "Time:" << key << "Operate:" << step->stepPrinter();
        }
    }
    qDebug() << "解析完毕 >>>>>>>>>>>>>>>>>>>>>>>>>>";

    return steps;

}





void AnimationParseExeConfig::execSteps(){

    if(!_controller){
        qDebug() << "ERROR: [Class]AnimationParseExecConfig [Func]ExecSteps - controller=nullptr";
        return;
    }
    _controller->clearFrameState();
//    double curTime = -1;
//    foreach(double time, _stepList.keys()){
//        if(curTime >= time){
//            continue;
//        }
//        curTime = time;
//        qDebug() << "Step at Time:" << time << " StepNum:" << _stepList.values(time).size();


//        QTimer* timer = new QTimer();
//        timer->start();
//        timer->setInterval(time * 1000);
//        connect(timer, &QTimer::timeout, [this, time, timer](){
//            auto stepList = _stepList.values(time);
//            foreach(Step* step, stepList){
//                execStep(step);
//            }
//            timer->stop();
//        });
//    }

    _state->reset();
    for(int i = 0; i < _maxFrame; i ++){
        auto stepList = _stepList.values(i);
        foreach(Step* step, stepList){
            execStep(step);
        }
        _controller->elapseFrame(i);
    }


}

void AnimationParseExeConfig::execStep(Step* step){

    if(!_state){
        qDebug() << "ERROR: [Class]AnimationParseExecConfig [Func]ExecStep - state=nullptr";
        return;
    }

//    qDebug() << step->stepPrinter();
    if(step->type == 0){
        _state->reset();
    }else if(step->type == 1){
        StepSyringe* stepS = dynamic_cast<StepSyringe*>(step);
        _state->changeSyringe(stepS->idx, stepS->posi, stepS->speed);
    }else if(step->type == 2){
        StepValve* stepV = dynamic_cast<StepValve*>(step);
        _state->changeValve(stepV->idx-1, stepV->state);
    }else if(step->type == 3){
        StepWheel* stepW = dynamic_cast<StepWheel*>(step);
        _state->turnWheel_posi(stepW->posi, stepW->direct, stepW->speed);
    }else if(step->type == 4){
        _state->pushHat();
    }else if(step->type == 5){
        StepDetector* stepD = dynamic_cast<StepDetector*>(step);
        _state->changeDetector(stepD->state);
    }
}



